package com.appspot.abcensys.shared;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.appspot.abcensys.server.DAO.JDO.LesDAO_JDO;


public class RoosterSupplier {
	
	// RoosterURL
	private final static String ROOSTER_URL = "http://www.nielstimmer.nl/hu/fetch.php";
	
	// JDO
	private LesDAO_JDO jdo = new LesDAO_JDO();
	
	// Logger
	private static final Logger log = Logger.getLogger(RoosterSupplier.class
			.getName());
	
	// FntRoosterInfo
	private FntRoosterInfo fri = new FntRoosterInfo();

	/**
	 * Leest de XML file van onze ROOSTER_URL, en parsed deze naar een rooster
	 * met lessen etc.
	 * @return 
	 */
	
	public void getRooster(Gebruiker g) {
		
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		
		// Bouw een nieuw document op, op basis van de rooster URL.
		try {
			DocumentBuilder db = dbf.newDocumentBuilder();

			//
			// Parameters instellen. Deze zijn terug te vinden in de source van
			// https://www.roosters.hu.nl/1112/huc/Default.aspx.
			//
			HashMap<String, String> params = new HashMap<String, String>();
			params.put("faculteit", g.getFaculteit());
			params.put("opleiding", g.getOpleiding());
			params.put("klas", g.getKlasCode());
			
			// Huidige weeknummer
			// TODO: moeten verdwijnen bij live gaan
			params.put("week", "45");
			
			// Huidige jaar
			// TODO: moeten verdwijnen bij live gaan
			params.put("jaar", "2011");

			String roosterUrl = this.getRoosterUrl(params);
			log.info("RooserURL: " + roosterUrl);
			Document doc = db.parse(roosterUrl);
			
			Element rooster = doc.getDocumentElement();
			String fack = rooster.getAttribute("faculteit");
			String ople = rooster.getAttribute("opleiding");
			int week = Integer.parseInt(rooster.getAttribute("week"));
			int jaar = Integer.parseInt(rooster.getAttribute("jaar"));
			
			// Zoek alle "les" elementen.
			NodeList nodeLst = doc.getElementsByTagName("les");
			for (int s = 0; s < nodeLst.getLength(); s++) {
				Node fstNode = nodeLst.item(s);

				if (fstNode.getNodeType() == Node.ELEMENT_NODE) {
					Les les = this.extractLes(fstNode);
					les.setFackulteit(fack);
					les.setOpleiding(ople);
					les.setWeekNummer(week);
					les.setJaar(jaar);
					log.info("Les is opgeslagen: " + jdo.addLes(les));
				}
			}
			
			// Haal de Rooster attributen op
			NodeList rstLst = doc.getElementsByTagName("rooster");
			for (int s = 0; s < rstLst.getLength(); s++) {
				Node rstNode = rstLst.item(s);

				if (rstNode.getNodeType() == Node.ELEMENT_NODE) {
					
				}
			}
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Retourneert een gepopuleerd Les-object, op basis van de opgegeven data.
	 * 
	 * @param fstNode
	 * @return
	 */
	
	private Les extractLes(Node fstNode) {
		
		// Dit les-object wordt gevuld met alle informatie die we hebben.
		Les les = new Les();

		//Ons les-element uit de XML
		Element lesElement = (Element) fstNode;
		
		// DATUM
		les.setLesDatum(this.getFirstElementTextValue(lesElement, "datum"));
		
		// Van
		les.setStartTijd(this.getFirstElementTextValue(lesElement, "van"));

		// Tot
		les.setEindTijd(this.getFirstElementTextValue(lesElement, "tot"));

		// Activiteit
		les.setVakCode(this.getFirstElementTextValue(lesElement, "activiteit"));
		
		// Groepen
		les.setKlasCode(fri.getKlasKey(this.getFirstElementTextValue(lesElement, "groepen")));

		// Docenten
		for (String docent : this.getFirstCollectionTextValues(lesElement, "docenten", "docent")) {
			les.addDocent(docent);
		}

		// Lokalen
		for (String lokaal : this.getFirstCollectionTextValues(lesElement, "lokalen", "lokaal")) {
			les.addLokaal(lokaal);
		}

		// Opmerkingen
		les.setOpmerking(this.getFirstElementTextValue(lesElement, "opmerkingen"));
		
		return les;
	}

	/**
	 * Retourneert de rooster URL, inclusief alle opgegeven parameters.
	 * 
	 * @param params
	 *            Een HashMap met alle parameters, niet ge-escaped.
	 * @return Een volledige URL met alle parameters erin.
	 */
	private String getRoosterUrl(HashMap<String, String> params) {
		if (params.size() == 0) {
			return ROOSTER_URL;
		}

		StringBuilder sb = new StringBuilder();

		sb.append(ROOSTER_URL);
		sb.append("?");

		for (Entry<String, String> entry : params.entrySet()) {
			try {
				sb.append(entry.getKey());
				sb.append("=");
				sb.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
				sb.append("&");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}

		return sb.toString();
	}

	/**
	 * Haalt de textuele waarde uit het eerste opgegeven element op.
	 * 
	 * @param element
	 *            Element waarin gezocht moet worden.
	 * @param name
	 *            Naam van het element waar de waarde van gezocht wordt.
	 * @return Textuele waarde van het gezochte element.
	 */
	private String getFirstElementTextValue(Element element, String name) {
		NodeList elementList = element.getElementsByTagName(name);
		Element resultElement = (Element) elementList.item(0);
		NodeList resultNode = resultElement.getChildNodes();

		return ((Node) resultNode.item(0)).getTextContent();
	}

	/**
	 * Haalt de textuele waarden uit het eerste opgegeven element, met de
	 * opgegeven children.
	 * 
	 * @param lesElement
	 *            Element waarin gezocht moet worden.
	 * @param container
	 *            Omliggende element.
	 * @param subject
	 *            Naam van het element waar de waarden van gezocht moeten
	 *            worden.
	 * @return Een ArrayList met alle gevonden waarden.
	 */
	
	private ArrayList<String> getFirstCollectionTextValues(Element lesElement, String container, String subject) {
		ArrayList<String> subjects = new ArrayList<String>();

		NodeList containerElementList = lesElement.getElementsByTagName(container);

		Element containerElement = (Element) containerElementList.item(0);

		NodeList subjectList = containerElement.getElementsByTagName(subject);
		for (int i = 0; i < subjectList.getLength(); i++) {
			Node subjectNode = subjectList.item(i);
			subjects.add(subjectNode.getTextContent());
		}

		return subjects;
	}
}
